package org.zhuzx.util;

import java.util.ArrayList;
import java.util.Arrays;

import org.zhuzx.util.pool.AbstractCachedPool;

/*
调用toString清空之后，length已经变了（应该加上temp长度），但仍能返回之前的所有内容，这是业务错误。
调用删除方法未去删除temp中的字符，也是业务错误，删除时甚至会报错，因为集合中的总字符数已经小于该值。
收集器缺temp，还是有性能缺憾。
考虑将temp以及删除temp尾部字符的操作独立为父类方法，两者都需要处理同时从temp和集合两者中删除的情况，可传入计算后的针对temp的删除字符数。
 */
@Deprecated
public class StringAppender {
	
	private Appender appender;
	
	private StringAppender(Appender appender) {
		this.appender = appender;
	}
	
	public StringAppender() {
		this(new Assimilator());
	}
	
	public StringAppender(int appendTimes) {
		this(new Collector(appendTimes));
	}
	
	public void append(String str) {
		if (str==null || str.length()==0) return;
		appender.append(str);
	}
	
	public void deleteLastChars(int length) {
		if (length < 0) throw new IllegalArgumentException();
		if (length == 0) return;
		if (length > appender.length()) throw new StringIndexOutOfBoundsException(length);
		appender.deleteLastChars(length);
	}
	
	public int length() {
		return appender.length();
	}
	
	public String toString() {
		return appender.toString();
	}
	
	private static interface Appender {
		public void append(String str);
		public void deleteLastChars(int length);
		public int length();
		public String toString();
	}
	
	private static class Assimilator implements Appender {
		private static final int MIN_ARRAY_SIZE = 4096;//一个普通的10行分页查询生成的json就很容易超过此长度
		private static final int MULTIPLICATION_EXPONENT = MicroUtil.findMinLogarithmOfTwo(MIN_ARRAY_SIZE);
		private static final int ARRAY_SIZE = 1 << MULTIPLICATION_EXPONENT;
		private static final AbstractCachedPool<char[]> pool = new AbstractCachedPool<char[]>(
				HardwareVariables.CPU_THREAD_NUM) {
			protected char[] create() {
				return new char[ARRAY_SIZE];
			}
		};
		private Node head;
		private Node last;
		private int fullNodeCount;
		private int cursor;
		private char[] temp = null;
		
		private static class Node {
			char[] array;
			Node prev;
			Node next;
			public Node(char[] array, Node prev) {
				this.array = array;
				this.prev = prev;
			}
		}
		
		public Assimilator() {
			init();
		}
		
		private void init() {
			head = new Node(pool.get(), null);
			last = head;
			fullNodeCount = 0;
			cursor = 0;
		}
		
		public void append(String str) {
			int length = str.length();
			int surplus = ARRAY_SIZE - cursor;
			if (length <= surplus) {
				str.getChars(0, length, last.array, cursor);
				cursor += length;
			} else {
				str.getChars(0, surplus, last.array, cursor);
				Node newLast = last.next;//last节点后面可能还有deleteLastChars方法产生的空节点
				if (newLast == null) {
					newLast = new Node(pool.get(), last);
					last.next = newLast;
				}
				str.getChars(surplus, length, newLast.array, 0);
				last = newLast;
				fullNodeCount++;
				cursor = length - surplus;
			}
		}
		
		public void deleteLastChars(int length) {
			if (length <= cursor) {
				cursor -= length;
			} else {
				int newCursor = cursor - length;
				while (newCursor < 0) {
					newCursor += ARRAY_SIZE;
					fullNodeCount--;
					last = last.prev;
				}
				cursor = newCursor;
			}
		}
		
		public int length() {
			return (fullNodeCount << MULTIPLICATION_EXPONENT) + cursor;
		}
		
		public String toString() {
			char[] value;
			if (fullNodeCount == 0) {
				value = Arrays.copyOf(head.array, cursor);
			} else {
				value = new char[length()];
				Node node = head;
				int pos = 0;
				for (int i=1; i<=fullNodeCount; i++) {
					System.arraycopy(node.array, 0, value, pos, ARRAY_SIZE);
					pos += ARRAY_SIZE;
					node = node.next;
				}
				System.arraycopy(node.array, 0, value, pos, cursor);
			}
			if (value.length > 0) {
				if (temp != null) {
					value = GeneralUtil.getCombinedArray(temp, value);
				}
				holdAndClear(value);
			} else {
				if (temp != null) {
					value = temp;
				}
			}
			return new String(value);
		}
		
		private void holdAndClear(char[] value) {
			temp = value;
			Node node = head;
			do {
				pool.giveBack(node.array);
				node = node.next;
			} while (node != null);
			init();
		}
	}
	
	private static class Collector implements Appender {
		private ArrayList<String> container;
		private int length = 0;

		public Collector(int appendTimes) {
			this.container = new ArrayList<>(appendTimes);
		}

		public void append(String str) {
			container.add(str);
			length += str.length();
		}

		public void deleteLastChars(int length) {
			String last = container.get(container.size() - 1);
			int endIndex = last.length() - length;
			while (endIndex < 0) {
				container.remove(container.size() - 1);
				last = container.get(container.size() - 1);
				endIndex += last.length();
			}
			container.set(container.size()-1, last.substring(0, endIndex));
			this.length -= length;
		}

		public int length() {
			return length;
		}
		
		public String toString() {
			char[] value = new char[length];
			int pos = 0;
			for (String str : container) {
				str.getChars(0, str.length(), value, pos);
				pos += str.length();
			}
			return new String(value);
		}
	}
	
}